package bma.common.netty.thrift.dual.impl;

import org.apache.thrift.TApplicationException;
import org.apache.thrift.TBase;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TMessage;
import org.apache.thrift.protocol.TMessageType;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TTransport;
import org.jboss.netty.channel.Channel;

import bma.common.netty.SupportedNettyChannel;
import bma.common.netty.thrift.core.NettyThriftConfig;
import bma.common.netty.thrift.core.TNettyFramedWriteOnlyTransport;
import bma.common.netty.thrift.dual.NCHThriftService;
import bma.common.netty.thrift.dual.NTSClient;
import bma.common.netty.thrift.dual.NTSRequest;

public class NTSRequestImpl implements NTSRequest, SupportedNettyChannel {

	private boolean done;

	private Channel channel;

	private TMessage message;

	private NettyThriftConfig config;

	private TProtocol inputProtocol;

	private TProtocol outputProtocol;

	public TMessage getMessage() {
		return message;
	}

	public void setMessage(TMessage message) {
		this.message = message;
	}

	public NettyThriftConfig getConfig() {
		return config;
	}

	public void setConfig(NettyThriftConfig config) {
		this.config = config;
	}

	public void setChannel(Channel channel) {
		this.channel = channel;
	}

	public void setInputProtocol(TProtocol inputProtocol) {
		this.inputProtocol = inputProtocol;
	}

	@Override
	public Channel getChannel() {
		return channel;
	}

	@Override
	public TMessage getHeader() {
		return message;
	}

	@Override
	public void setHeader(TMessage msg) {
		message = msg;
	}

	@Override
	public TProtocol getInputProtocol() {
		return inputProtocol;
	}

	@Override
	public TProtocol getOutputProtocol(boolean newOne) {
		if (newOne) {
			outputProtocol = null;
		}
		if (outputProtocol != null)
			return outputProtocol;
		TTransport trans = new TNettyFramedWriteOnlyTransport(channel,
				config.getMaxLength());
		outputProtocol = config.getProtocol(trans);
		return outputProtocol;
	}

	public <TYPE extends TBase> TYPE readArgs(TYPE args) throws TException {
		TProtocol iprot = getInputProtocol();
		args.read(iprot);
		iprot.readMessageEnd();
		return args;
	};

	@Override
	public void end(TBase data, Throwable err) {
		if (done) {
			return;
		}
		done = true;
		
		TMessage msg = getHeader();
		if (msg.type == TMessageType.ONEWAY)
			return;
		try {
			TProtocol oprot = getOutputProtocol(true);
			if (err != null) {
				TApplicationException x;
				if (err instanceof TApplicationException) {
					x = (TApplicationException) err;
				} else {
					x = new TApplicationException(
							TApplicationException.PROTOCOL_ERROR,
							err.getMessage());
				}
				oprot.writeMessageBegin(new TMessage(msg.name,
						TMessageType.EXCEPTION, msg.seqid));
				x.write(oprot);
			} else {
				oprot.writeMessageBegin(new TMessage(msg.name,
						TMessageType.REPLY, msg.seqid));
				data.write(oprot);
			}
			oprot.writeMessageEnd();
			oprot.getTransport().flush();
		} catch (Exception ex) {
			// skip
		}
	}

	@Override
	public NTSClient getClient() {
		return NCHThriftService.getNTSClientFromChannel(channel);
	}
}
